--- /dev/null
+Using gpsbabel to create MS 2002 Pushpin Files
+----------------------------------------------
+
+The standard S&T method:
+ 1. Create pushpins in S&T 2002 either by click-and-create or by importing
+ from a CSV format file (A header line helps greatly decrease the time
+ spent in the import data wizard).
+ 2. Select the map region you wish to create.
+ 3. Wait a couple of dozen minutes for the map to export.
+ 4. Copy map and corresponding .psp file to a folder on the mobile device.
+ 5. Open map in pocketstreets.
+
+The gpsbabel/psp method:
+ 1. Be sure you've already created the map/region.
+ (in this case, Lafayette.mps).
+ 2. Run gpsbabel with .psp output.
+ (i.e. gpsbabel -i geo -f geocaching.loc -o psp -F Lafayette.psp)
+ 3. Open map in pocketstreets.
+
+Notes in general:
+ o PocketStreets loads pushpins files with the same name as the MAP
+ being loaded. So if you have a map, "Lafayette.mps", the
+ corresponding set of pins should be called "Lafayette.psp".
+ These two files need to be in the same "folder" on the mobile
+ device in order for things to work properly (waah!).
+
+ o Pocketstreets re-writes pushpin files every time you open and
+ close the map. Doing so sometimes re-sizes the pushpin files.
+ That's OK.
+
+ o Pocketstreets won't choke on pushpins that are not for the map
+ being viewed, it simply "grays" them out in Pushpin Explorer.
+ This lets us make one HUGE pushpin file that covers dozens of
+ maps.
+
+
+Example Usage:
+ o I get 2 files from geocaching.com on a regular basis, each
+ containing a couple-of-hundred waypoints.
+
+ o I have a directory.. err.. folder on my hard drive located at
+ c:\makefiles.
+
+ o In that directory, I keep a batch file called "makefiles.bat" that
+ looks like this:
+
+ @echo off
+
+ REM *** EXPERTGPS GPX FORMAT ***
+ REM *** NOTE THAT -x n IS NOT A STANDARD GPSBABEL FEATURE ***
+ gpsbabel -i geo -f 51.loc -f 61.loc -x n -o gpx -F e:\expertgps\geocaches.gpx
+
+ REM *** FILES FOR MAGELLAN SD CARD ***
+ gpsbabel -i gpx -f e:\expertgps\geocaches.gpx -o magellan -F geocache.wpt
+
+ REM *** BASE FILE FOR POCKETSTREETS PUSHPINS ***
+ REM *** NOTICE "-s" TO SYNTHESIZE SHORTNAMES ***
+ gpsbabel -s -i gpx -f e:\exertgps\geocaches.gpx -o psp -F geocache.psp
+
+ REM *** MULTIPLY PUSHPINS ONTO IPAQ ***
+ copy geocache.psp C:\"My Documents\Pocket_PC My Documents"\Incoming\Lafayette.psp
+ copy geocache.psp C:\"My Documents\Pocket_PC My Documents"\Incoming\BatonRouge.psp
+ copy geocache.psp C:\"My Documents\Pocket_PC My Documents"\Incoming\NewOrleans.psp
+ copy geocache.psp C:\"My Documents\Pocket_PC My Documents"\Incoming\Houston.psp
+
+ o When I get my .loc files from geocaching.com, I stick them in the
+ "c:\makefiles" directory and run "makefiles.bat". when the batch
+ file is complete in a few seconds, I have managed to do accomplish
+ a few things that used to be some cumbersome they weren't even worth
+ doing:
+
+ 1. I have a "Magellan Protocol" text file to load onto my Meridian's
+ SD card containing all of the geocaches from those 2 files.
+
+ 2. I have created pushpins for 4 seperate maps. Since I'm putting them
+ in the "Pocket_PC My Documents\Incoming" folder, they will auto-sync
+ to my iPaq when it syncs. Since I store my maps on my iPaq's SD card,
+ I need to move these over to my maps folder by hand later. That takes
+ all of about 10 seconds.
+
+ 3. It is my preference to have "synthesized shortnames" on my pushpin
+ files instead of geocaching.com "GCXXXX" names. Since the shortname
+ synthesizer for pushpins is set to around 32 bytes, instead of seeing
+ "GCF00D" as a pushpin name, I see "Swinging Rope Bridge."
+
#endif
-static int
-valid_psp_header(char * header, int len)
+/* Implement the grid in ascii art... This makes a bit of sense if you stand
+ on a point over the north pole and look down on the earth.
+
+-180 -90 0 90 180
+------------------------------------ /\
+| 0x03 U|S 0x02 U|k 0x00 | 0x01 | 90
+|--------|--------|--------|--------| 0
+| 0x07 | 0x06 | 0x04 | 0x05 | -90
+------------------------------------ \/
+*/
+static
+char grid_byte(double lat, double lon)
{
- char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50, 0x00 }; /* 1niP <stop> */
- char *p, *s;
-
- if (len != 32) {
- return (-1);
+ char c = 0x00;
+
+ if ((lon >= 0.0) && (lon < 90.0)) {
+ if (lat >= 0.0) {
+ c = 0x00;
+ } else {
+ c = 0x04;
+ }
+ } else
+ if (lon >= 90.0) {
+ if (lat >= 0.0) {
+ c = 0x01;
+ } else {
+ c = 0x05;
+ }
+ } else
+ if ((lon < 0.0) && (lon >= -90.0)) {
+ if (lat >= 0.0) {
+ c = 0x02;
+ } else {
+ c = 0x06;
+ }
+ } else
+ if (lon < -90.0) {
+ if (lat >= 0.0) {
+ c = 0x03;
+ } else {
+ c = 0x07;
+ }
}
+
+ return (c);
+}
- p = header_bytes;
- s = header;
-
- while (*p) {
- if (*p++ != *s++) {
- return(-1);
- }
+void decode_psp_coordinates(double * lat, double * lon, const char lonbyte)
+{
+ /* This is some sort of 1/2 Polar, 1/2 Cartesian coordinate mess in */
+ /* the pin file. I really shouldn't have to do this. Zones 02 and 03 */
+ /* work properly. The other zones are assumptions based on 02 and 03 */
+
+ if ((lonbyte == 0x02) || (lonbyte == 0x06)) {
+ /* one step west of zero longitude */
+ if (*lon > 0.0)
+ *lon *= -1.0;
+ } else
+ if ((lonbyte == 0x03) || (lonbyte == 0x07)) {
+ /* two steps west of zero longitude */
+ if (*lon > 0.0)
+ *lon -= 180.0;
+ } else
+ if ((lonbyte == 0x00) || (lonbyte == 0x04)) {
+ /* one step east of zero longitude */
+ if (*lon < 0.0)
+ *lon *= -1.0;
+ } else
+ if ((lonbyte == 0x01) || (lonbyte == 0x05)) {
+ /* two steps east of zero longitude */
+ if (*lon < 0.0)
+ *lon += 180.0;
}
+}
+
+static int
+valid_psp_header(char * header)
+{
+ char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50 }; /* 1niP <stop> */
- return (0);
+ return (memcmp(header_bytes, header, 4));
+
}
static char *
{
char buff[MAXPSPSTRINGSIZE + 1];
double radians;
+ double lat, lon;
waypoint *wpt_tmp;
int stringsize;
short int pincount;
+ short int pindex;
+ char gridbyte = 0x00;
/* 32 bytes - file header */
psp_fread(&buff[0], 1, 32, psp_file_in);
- if (valid_psp_header(buff, 32) != 0) {
+ if (valid_psp_header(buff) != 0) {
fatal(MYNAME ": input file does not appear to be a valid .PSP file.\n");
}
while (pincount--) {
wpt_tmp = xcalloc(sizeof(*wpt_tmp),1);
- /* things we will probably never know about this waypoint */
- /* coming from a pushpin file. */
-
- /*
- wpt_tmp->creation_time;
- wpt_tmp->position.altitude.altitude_meters;
- wpt_tmp->url;
- wpt_tmp->url_link_text;
- wpt_tmp->icon_descr; TODO: map this.
- */
+ wpt_tmp->position.altitude.altitude_meters = unknown_alt;
+
+ /* offset 0x20 - 0x21 pin index */
+ psp_fread(&pindex, 1, 2, psp_file_in);
- /* 4 bytes at start of record */
- /* coming out of S&T, this 1st byte is probably the pin # (0x01, 0x02, etc...) */
- /* coming from pocketstreets, it's generally 0x00. Sometimes 0xC3. ? */
+ /* offset 0x22 - 0x23 */
+ psp_fread(&buff[0], 1, 2, psp_file_in);
- psp_fread(&buff[0], 1, 4, psp_file_in);
-
- /* 1 byte, unkown */
- psp_fread(&buff[0], 1, 1, psp_file_in);
+ /* offset 0x24 */
+ /* 1 byte, the grid byte - needed for sign corrections later*/
+ psp_fread(&gridbyte, 1, 1, psp_file_in);
/* 8 bytes - latitude in radians */
radians = psp_fread_double(psp_file_in);
- wpt_tmp->position.latitude.degrees = (radians * 180.0) / M_PI;
+ lat = (radians * 180.0) / M_PI;
/* 8 bytes - longitude in radians */
radians = psp_fread_double(psp_file_in);
- wpt_tmp->position.longitude.degrees = (radians * 180.0) / M_PI;
+ lon = (radians * 180.0) / M_PI;
+
+ /* since we don't know the origin of this PSP file, we use */
+ /* the grid byte adjust longitude, if necessary, mimicing */
+ /* the behavior of pocketstreets correcting the data. This */
+ /* does not correct the fact that points in eastern US are */
+ /* written with the wrong coordinates by S&T. (MS bug) */
+ decode_psp_coordinates(&lat, &lon, gridbyte);
+
+ wpt_tmp->position.latitude.degrees = lat;
+ wpt_tmp->position.longitude.degrees = lon;
+
/* 1 byte - pin display properties */
psp_fread(&buff[0], 1, 1, psp_file_in);
/* 3 bytes - unknown */
psp_fread(&buff[0], 1, 3, psp_file_in);
- /* 1 bytes - icon 0x00 - 0x27 */
+ /* 1 bytes - icon (values: 0x00 - 0x27) */
psp_fread(&buff[0], 1, 1, psp_file_in);
/* 3 bytes - unknown */
char tbuf[64];
char c;
int i;
+ static short int pindex = 0;
char *shortname;
char *description;
/* convert lat/long back to radians */
lat = (wpt->position.latitude.degrees * M_PI) / 180.0;
lon = (wpt->position.longitude.degrees * M_PI) / 180.0;
-
- /* 4 leading bytes */
+
+ pindex++;
+ le_write16(tbuf, pindex);
+ /* 2 bytes - pin index */
+ fwrite(tbuf, 1, 2, psp_file_out);
+
+ /* 2 bytes - null bytes */
memset(tbuf, '\0', sizeof(tbuf));
- fwrite(tbuf, 1, 4, psp_file_out);
-
- /* my test files seem to always have this byte as 0x03, */
- /* although nothing seems to really care. */
- c = 0x03;
+ fwrite(tbuf, 1, 2, psp_file_out);
+
- /* 1 unknown bytes */
+ /* set the grid byte */
+ c = grid_byte(wpt->position.latitude.degrees,
+ wpt->position.longitude.degrees);
+
+ /* since the grid byte matches with what pocketstreets does to */
+ /* input files, our output appears identical to a pin file that */
+ /* has already been processed and corrected by pocketstreets. */
+ /* Due to the grid and signs, it'll look different than one that */
+ /* comes straight from S&T. */
+
+ /* the grid byte */
fwrite(&c, 1, 1, psp_file_out);
/* 8 bytes - latitude/radians */
psp_fwrite_double(lon, psp_file_out);
/* 1 byte - pin properties */
- c = 0x14; /* display pin name on! display notes on! */
+ c = 0x14; /* display pin name on, display notes on. 0x04 = no notes */
fwrite(&c, 1, 1, psp_file_out);
memset(tbuf, '\0', sizeof(tbuf));